import datetime

from django.apps import apps
from django.contrib import messages
from django.contrib.auth.mixins import (
    PermissionRequiredMixin,
)
from django.core.urlresolvers import reverse_lazy
from django.forms.models import modelform_factory
from django.shortcuts import get_object_or_404, redirect
from django.views.generic import (
    CreateView, ListView, TemplateView, UpdateView, View
)
from django.utils import timezone

from common.constants import PERMS
from common.mixins import UserCourseRelatedMixin, SidebarMixin
from common.mixins import PageinatorMixin
from common.utils import get_dt
from common.forms import SelectAssigneeForm
from user.models import User
from exam.models import ExamPaper
from resume.models import Resume
from interview.models import Interview
from .constants import MODULE_CONTENT_LIST, MODULE_CONTENT_PROBLEM
from .forms import LectureForm
from user.forms import HorizontalFormHelper
from .models import Course, Lecture


class CourseActionMixin(object):
    fields = '__all__'
    model = Course
    success_url = reverse_lazy('course:list')

    @property
    def success_msg(self):
        return NotImplemented

    def form_valid(self, form):
        messages.info(self.request, self.success_msg)
        return super(CourseActionMixin, self).form_valid(form)


class CourseListView(PermissionRequiredMixin, SidebarMixin, ListView):
    model = Course
    template_name = 'course/list.html'
    permission_required = (PERMS.IS_SUPERVISOR,)

    @property
    def section_title(self):
        return 'Course Management'

    @property
    def course_list_class(self):
        return 'active'

    @property
    def search_url(self):
        return 'course:list'

    def get_queryset(self):
        queryset = super(CourseListView, self).get_queryset()

        q = self.request.GET.get('q')
        if q:
            return queryset.filter(title__icontains=q)

        return Course.objects.all()

    def get_context_data(self, **kwargs):
        context = super(CourseListView, self).get_context_data(**kwargs)
        q = self.request.GET.get('q')
        if q:
            context['q'] = q
        return context


class CourseCreateView(PermissionRequiredMixin, SidebarMixin,
                       CourseActionMixin, CreateView):
    success_msg = 'course created'
    template_name = 'course/create_or_update.html'
    permission_required = ('course.add_course',)

    # template used variables
    section_title = 'Create Course'
    course_create_class = 'active'
    submit_text = 'Create'
    form_helper = HorizontalFormHelper()


class CourseUpdateView(SidebarMixin, CourseActionMixin, UpdateView):
    success_msg = 'course updated'
    template_name = 'course/create_or_update.html'
    permission_required = ('course.update_course',)

    # template used variables
    section_title = 'Manage Course'
    course_list_class = 'active'
    submit_text = 'Update'
    form_helper = HorizontalFormHelper()


class LectureView(UserCourseRelatedMixin, SidebarMixin, TemplateView):
    template_name = 'course/teacher/lecture.html'
    section_title = 'Create Lecture'

    course = None
    lecture = None

    def dispatch(self, request, course_id, lecture_id=None):
        self.course = get_object_or_404(Course, id=course_id)
        self.course_id = course_id
        self.course_slug = self.course.slug
        if lecture_id:
            self.lecture = get_object_or_404(Lecture, id=lecture_id)
            self.section_title = 'Edit Lecture'
        self.success_url = reverse_lazy(
            'course:calendar', kwargs={'pk': course_id})
        return super(LectureView, self).dispatch(
            request, course_id, lecture_id)

    def get(self, request, course_id, lecture_id=None):
        if not lecture_id:
            dt = get_dt(request.GET['year'],
                        request.GET['month'], request.GET['day'])
            data = {
                'start': dt,
                'end': dt,
                'course': self.course,
                'notes' : '##Title Here \n input your lecture here...'
            }
            form = LectureForm(initial=data)
        else:
            form = LectureForm(instance=self.lecture)
        return self.render_to_response({
            'view': self,
            'form': form,
        })

    def post(self, request, course_id, lecture_id=None):
        form = LectureForm(data=request.POST, instance=self.lecture)
        if form.is_valid():
            form.save()
            return redirect('course:calendar', course_id)
        else:
            return self.render_to_response({
                'view': self,
                'form': form,
            })


class CourseCalendarView(UserCourseRelatedMixin, SidebarMixin, TemplateView):
    template_name = 'course/teacher/calendar.html'
    section_title = 'Manage Course Modules'

    course = None

    def dispatch(self, request, pk):
        self.course = get_object_or_404(Course, id=pk)
        self.course_id = self.course.id
        return super(CourseCalendarView, self).dispatch(request, pk)


class ModuleListView(SidebarMixin, TemplateView):
    template_name = 'course/module/list.html'
    module = None
    section_title = 'Manage Contents'

    is_exam = False

    @property
    def is_module_list_page(self):
        return True

    def dispatch(self, request, module_id):
        self.module = get_object_or_404(Module, id=module_id,)
        first = self.module.contents.first()
        if first and isinstance(first.item, Problem):
            self.is_exam = True

        return super(ModuleListView, self).dispatch(request, module_id)

    def get(self, request, module_id):
        return self.render_to_response({
            'view': self,
            'module': self.module,
            'exam_form': ExamModuleForm(instance=self.module),
        })

    def post(self, request, module_id):
        form = ExamModuleForm(request.POST, instance=self.module)
        if form.is_valid():
            module = form.save()
            module.start = timezone.now()
            module.save()
            # update problem time
            if module.exam_started:
                start = module.start
                for content in module.contents.all():
                    problem = content.item
                    problem.start = start
                    problem.save()
                    start = start + datetime.timedelta(minutes=problem.minutes)

        return self.render_to_response({
            'view': self,
            'module': self.module,
            'exam_form': ExamModuleForm(instance=self.module),
        })


class ContentCreateUpdateView(SidebarMixin, TemplateView):
    module = None
    model = None
    model_name = None
    obj = None
    template_name = 'course/module/content/form.html'

    is_module_list_page = True

    def get_model(self, model_name):
        if model_name in MODULE_CONTENT_LIST:
            return apps.get_model(app_label='course', model_name=model_name)
        return None

    def get_form(self, model, *args, **kwargs):
        if self.model_name == MODULE_CONTENT_PROBLEM:
            fields = ['content', 'minutes']
        else:
            fields = ['content']

        Form = modelform_factory(
            model,
            fields=fields,
            # exclude=['order', 'created', 'updated']
        )
        return Form(*args, **kwargs)

    def dispatch(self, request, module_id, model_name, id=None):
        self.module = get_object_or_404(Module, id=module_id)
        self.model = self.get_model(model_name)
        self.model_name = model_name
        if id:
            self.obj = get_object_or_404(self.model, id=id)
        return super(ContentCreateUpdateView,
                     self).dispatch(request, module_id, model_name, id)

    def get(self, request, module_id, model_name, id=None):
        form = self.get_form(self.model, instance=self.obj)
        return self.render_to_response({
            'form': form,
            'object': self.obj,
            'view': self,
        })

    def post(self, request, module_id, model_name, id=None):
        form = self.get_form(self.model,
                             instance=self.obj,
                             data=request.POST,
                             files=request.FILES)
        if form.is_valid():
            obj = form.save(commit=False)
            obj.save()
            if not id:
                # new content
                Content.objects.create(module=self.module,
                                       item=obj)
            return redirect('course:list_modules', self.module.id)

        return self.render_to_response({
            'form': form,
            'object': self.obj,
            'view': self,
        })


class ContentDeleteView(View):

    def post(self, request, id):
        content = get_object_or_404(Content, id=id)
        module = content.module
        content.item.delete()
        content.delete()
        return redirect('course:list_modules', module.id)


class CourseStudentListView(
        UserCourseRelatedMixin, SidebarMixin,
        ListView, PageinatorMixin):

    course = None
    section_title = 'Manage Class Students'
    taskselect = None
    template_name = 'user/teacher/course_students.html'
    context_object_name = 'user_list'

    @property
    def search_url(self):
        return 'course:students'

    @property
    def search_url_para(self):
        return self.course.id

    def __init__(self, **kwargs):
        super(CourseStudentListView, self).__init__(**kwargs)

    def dispatch(self, request, pk):
        self.course = get_object_or_404(Course, id=pk)
        self.course_id = pk
        self.taskselect = SelectAssigneeForm()
        return super(CourseStudentListView, self).dispatch(request, pk)

    def get_queryset(self):
        queryset = self.course.students.all()
        queryset = super(CourseStudentListView, self).filter_queryset(
            queryset)
        return queryset

    def render_to_response(self, context, **response_kwargs):
        return super(CourseStudentListView, self).render_to_response(
            context, **response_kwargs
        )

    def get_context_data(self, **kwargs):
        context = super(CourseStudentListView, self).get_context_data(**kwargs)

        q = self.request.GET.get('q')
        if q:
            context['q'] = q

        context['exams'] = self.course.exams.all()

        return context


class CourseUnitedStudentListView(UserCourseRelatedMixin,
                                  SidebarMixin,
                                  ListView,
                                  PageinatorMixin):

    template_name = 'user/teacher/course_students.html'
    context_object_name = 'user_list'

    section_title = 'Course Students List'

    taskselect = None
    is_slug_view = True

    @property
    def search_url(self):
        return 'course:united_students'

    @property
    def search_url_para(self):
        return self.course_slug

    def dispatch(self, request, slug):
        self.course_slug = slug
        self.taskselect = SelectAssigneeForm()
        return super(CourseUnitedStudentListView, self).dispatch(
            request, slug)

    def get_queryset(self):
        queryset = User.objects.none()
        for course in Course.objects.filter(slug=self.course_slug):
            if course not in self.request.user.teaching.all():
                continue
            students = course.students.all()
            queryset = queryset | students
        queryset = queryset.distinct()
        queryset = super(
            CourseUnitedStudentListView, self).filter_queryset(queryset)
        return queryset

    def render_to_response(self, context, **response_kwargs):
        return super(CourseUnitedStudentListView, self).render_to_response(
            context, **response_kwargs
        )

    def get_context_data(self, **kwargs):
        context = super(
            CourseUnitedStudentListView, self).get_context_data(**kwargs)

        q = self.request.GET.get('q')
        if q:
            context['q'] = q

        exams = []
        # for module in self.course.modules.all():
        #     for content in module.contents.all():
        #         if isinstance(content.item, Problem):
        #             exams.append(module)
        #             break
        context['exams'] = exams
        context['request'] = self.request
        return context


class LectureStudentView(SidebarMixin, TemplateView):
    template_name = 'course/lecture.html'
    lecture = None

    def dispatch(self, request, lecture_id):
        self.lecture = get_object_or_404(Lecture, id=lecture_id)
        self.course_id = self.lecture.course.id
        self.course_title = self.lecture.course.title

        return super(LectureStudentView, self).dispatch(request, lecture_id)

    def get(self, request, lecture_id):
        return self.render_to_response({
            'view': self,
            'lecture': self.lecture
        })


class StudentDetailView(SidebarMixin, TemplateView):
    template_name = 'course/teacher/student_detail.html'
    section_title = 'student details'

    student = None
    interviews = None
    exam_papers = None

    def set_exam_papers(self):
        self.exam_papers = []
        for course in self.student.enrolling.all():
            if course not in self.request.user.teaching.all():
                continue
            for exam in course.exams.all():
                exam_paper = ExamPaper.objects.filter(
                    exam=exam, student=self.student)
                if exam_paper:
                    self.exam_papers.append(exam_paper[0])
                break

    def get_resume_obj(self, user):
        result = {}
        resume_types = user.resumes.values('desc').distinct()
        for resume_type in resume_types:
            resume = Resume.objects.filter(
                user=user, desc=resume_type['desc']).last()
            result[resume_type['desc']] = resume

        return result

    def dispatch(self, request, pk, course_id=None, slug=None):
        self.student = get_object_or_404(User, id=pk)
        self.course_id = course_id
        self.course_slug = slug

        self.interviews = Interview.objects.filter(
            interviewee=self.student, interviewer=request.user)
        self.set_exam_papers()

        return super(StudentDetailView,
                     self).dispatch(request, pk, course_id, slug)

    def get(self, request, pk, course_id=None, slug=None):
        return self.render_to_response({
            'view': self,
            'student': self.student,
            'resume_obj': self.get_resume_obj(self.student),
        })


class AdminCalendarView(SidebarMixin, TemplateView):

    template_name = 'course/supervisor/calendar.html'
    section_title = 'Courses calendar view'
    course_calendar_class = 'active'
